import { html, css, repeat, when } from '@microsoft/fast-element'; import { LitroPage } from '@beatzball/litro/adapter/fast/page'; import { definePageData } from '@beatzball/litro'; import { createError } from 'h3'; import type { Post } from 'litro:content'; import { getPosts } from 'litro:content'; import { siteConfig } from '../../server/starlight.config.js'; import { extractHeadings, addHeadingIds } from '../../src/extract-headings.js'; import { starlightHead } from '../../src/route-meta.js'; import { formatDate, isoDate } from '../../src/date-utils.js'; // Register components — namespace imports prevent Rollup tree-shaking. import * as _starlightHeader from '../../src/components/starlight-header.js'; globalThis.__litro_ce__ = { ...(globalThis as any).__litro_ce__, _starlightHeader }; export interface BlogPostData { post: Post; body: string; toc: Array<{ depth: number; text: string; slug: string }>; siteTitle: string; nav: typeof siteConfig.nav; } export const pageData = definePageData(async (event) => { const slug = event.context.params?.slug ?? ''; // Content URLs are /content/blog/ (contentDir = 'content') const posts = await getPosts(); const post = posts.find(p => p.url === `/content/blog/${slug}`); if (!post) { throw createError({ statusCode: 404, message: `Post not found: ${slug}` }); } const toc = extractHeadings(post.rawBody); const body = addHeadingIds(post.body); return { post, body, toc, siteTitle: siteConfig.title, nav: siteConfig.nav, } satisfies BlogPostData; }); export async function generateRoutes(): Promise { const posts = await getPosts(); return posts .filter(p => p.url.startsWith('/content/blog/')) .map(p => '/blog' + p.url.slice('/content/blog'.length)); } export const routeMeta = { head: starlightHead, title: 'Blog — {{projectName}}', }; export class BlogPostPage extends LitroPage {} const template = html` ${(x) => { const data = x.serverData as BlogPostData | null; if (!data?.post) return html`

Loading…

`; const { post, body, siteTitle, nav } = data; const blogSlug = post.url.slice('/content/blog/'.length); const visibleTags = post.tags.filter(t => t !== 'posts'); return html`

${() => post.title}

${when(() => visibleTags.length > 0, html`
${repeat(() => visibleTags, html` #${x => x} `)}
`)}
`; }} `; const styles = css``; BlogPostPage.define({ name: 'page-blog-slug', template, styles }); export default BlogPostPage;